import numpy as np  # 导入numpy库
import pandas as pd  # 导入pandas库
from sklearn.ensemble import GradientBoostingRegressor  # 集成方法回归库
from sklearn.model_selection import GridSearchCV  # 导入交叉检验库
import matplotlib.pyplot as plt  # 导入图形展示库
from sklearn.metrics import mean_squared_error as mse
import time
#加载多线程
from threading import Thread



class Model:
    def __init__(self):
        pass

    def main(self):
        self.raw_data = pd.read_table('products_sales.txt', delimiter=',')
        # 数据概览
        print('{:*^60}'.format('Data overview:'), '\n', self.raw_data.tail(2))  # 打印原始数据后2条
        print('{:*^60}'.format('Data dtypes:'), '\n', self.raw_data.dtypes)  # 数据类型
        #加载缺失值审查
        a = self.loss_nan()
        # 分割数据集X和y
        num = int(0.7 * a.shape[0])
        X, y = a.iloc[:, :-1], a.iloc[:, -1]
        self.X_train, self.X_test = X.iloc[:num, :], X.iloc[num:, :]
        self.y_train, self.y_test = y.iloc[:num], y.iloc[num:]

        #加载训练模型
        self.train_model()
    #缺失值审查
    def loss_nan(self):
        na_cols = self.raw_data.isnull().any(axis=0)  # 查看每一列是否具有缺失值
        print('{:*^60}'.format('NA Cols:'))
        print(na_cols[na_cols] == True)  # 查看具有缺失值的列
        print('Total NA lines is: {0}'.format(self.raw_data.isnull().any(axis=1).sum()))  # 查看
        # 缺失值处理
        sales_data = self.raw_data.fillna(self.raw_data['price'].mean())  # 缺失值替换为均值
        return sales_data

    #模型训练
    def train_model(self):
        model_gbr = GradientBoostingRegressor()  # 建立GradientBoostingRegressor回归对象

        # loss{‘squared_error’, ‘absolute_error’, ‘huber’, ‘quantile’}, default=’squared_error’
        parameters = {'loss': ['squared_error', 'absolute_error', 'huber', 'quantile'],
                      'n_estimators': [10, 50, 100],
                      'learning_rate': [0.05, 0.1, 0.15],
                      'max_depth': [2, 3, 4],
                      'min_samples_split': [2, 3, 5],
                      'min_samples_leaf': [1, 2, 4]}  # 定义要优化的参数信息
        model_gs = GridSearchCV(estimator=model_gbr,
                                param_grid=parameters, cv=3, n_jobs=-1)  # 建立交叉检验模型对象
        model_gs.fit(self.X_train, self.y_train)  # 训练交叉检验模型
        print('Best score is:', model_gs.best_score_)  # 获得交叉检验模型得出的最优得分
        print('Best parameter is:', model_gs.best_params_)  # 获得交叉检验模型得出的最优参数

        # 获取最佳训练模型
        self.model_best = model_gs.best_estimator_  # 获得交叉检验模型得出的最优模型对象
        print('模型已经训练好了!')

    def pg_model(self):
        # 模型交叉检验结果
        # print(model_gs.cv_results_.keys())
        self.model_gs.cv_results_.get('mean_test_score')

        # 回归指标评估
        pre_test = self.model_best.predict(self.X_test)
        self.mse_score = mse(pre_test, self.y_test)

    def painting(self):
        plt.style.use("ggplot")  # 应用ggplot自带样式库
        plt.figure(figsize=(10, 7))  # 建立画布对象
        plt.plot(np.arange(self.X_test.shape[0]), self.y_test, linestyle='-', color='k', label='true y')  # 画出原始变量的曲线
        plt.plot(np.arange(self.X_test.shape[0]), self.pre_test, linestyle=':', color='m',
                 label='predicted y')  # 画出预测变量曲线
        plt.title('best model with mse of {}'.format(int(self.mse_score)))
        plt.legend(loc=0)  # 设置图例位置


if __name__=='__main__':
    mql_self=Model()
    #先读取数据
    # mql_self.main()
    add_thread = Thread(target=mql_self.main())
    desc_thread = Thread(target=mql_self.train_model())
    add_thread.start()
    desc_thread.start()







